-- UIPkgDownload
-- Create by zouyb Nov/7/2015
-- 独立包更新界面

-- 本地manifest的路径
local sceneManifests    = "manifest/project.manifest";
local versionManifests  = "manifest/version.manifest";

-- 下载资源保存的路径
local storagePaths = "update_res/";

-- UIPkgDownload继承自Layer
UIPkgDownload = class("UIPkgDownload", function()
    return cc.Layer:create();
end);

function UIPkgDownload.create(title, desc, targetPart, callback, targetVersion)
    return UIPkgDownload.new(title, desc, targetPart, callback, targetVersion);
end

-- 进度条光效偏移
local offsetX = 0;
local offsetY = 25;

-- 草地偏移
local grassOffset = ({18, 40, 60, 74, 82});

-- 长花的概率
local flowerProb = 50;

-- 内部函数声明

-- 构造函数
function UIPkgDownload:ctor(title, desc, targetPart, callback, targetVersion)
    -- 加载合图
    cc.SpriteFrameCache:getInstance():addSpriteFrames("images/ui/login_effect.plist");

    -- 初始化
    self:setName("UIPkgDownload");
    local node = cc.CSLoader:createNode("layout/download/PkgDownload.csb");
    self:addChild(node);
    self.node = node;

    self:setLocalZOrder(UIMgr.BONUS_NOTIFY_ZORDER + 1000);
    self.BT = findChildByName(self.node, "BT");
    self.logLabel = findChildByName(self.BT, "log");

    self.progressLabel = findChildByName(self.BT, "progress_label");
    self.progressLabel:setVisible(false);

    self.title = title;
    self.targetPart = targetPart;
    self.callback = callback;
    self.targetVersion = targetVersion;

    self.loadingBar1BG = findChildByName(self.BT, "progress_bg");

    -- 进度条动画
    local pNode = cc.Node:create();
    local barEffect = ccui.ImageView:create();
    barEffect:loadTexture("images/ui/login/effect/progress_gb.png");
    barEffect:setAnchorPoint(cc.p(0.5, 0));
    self.barEffect = barEffect;
    pNode:addChild(barEffect);
    self.pNode = pNode;
    self.pNode:setPosition(0, self.loadingBar1BG:getPositionY() + 25);
    self.BT:addChild(self.pNode);
    self.pNode:setVisible(false);

    -- 限定只允许一个下载目标
    if self.targetVersion == nil and #string.explode(self.targetPart, "|") > 1 then
        error("只允许设置一个下载目标");
    end

    -- 初始化下载管理器
    local am = cc.AssetsManagerEx:create(sceneManifests, cc.FileUtils:getInstance():getWritablePath() .. storagePaths, self.targetPart.."_zip");
    print(cc.FileUtils:getInstance():getWritablePath() .. storagePaths);

    local dowloadRootUrl = _G["dislist"]["download_root_url"];
    if dowloadRootUrl ~= nil and dowloadRootUrl ~= "" then
        am:setDownloadRootUrl(dowloadRootUrl);

        -- 如果目标版本不为nil，表示需要强制更新到目标版本，需要设置强制下载标记
        if self.targetVersion ~= nil then
            local currentVersion = am:getLocalManifest():getVersion();
            if self.targetVersion == currentVersion then
                -- 已经是最新版本，无需更新
                self.noNeedToDownload = true;
                return;
            end

            -- 只要版本号不一致就更新，相当于可以支持回退版本
            -- (一般是要版本号大于本地版本才更新)
            am:setDownloadWhenMismatch();

            -- 重新设置目标下载URL
            dowloadRootUrl = string.gsub(dowloadRootUrl, "latest",  self.targetVersion);
            am:setDownloadRootUrl(dowloadRootUrl);
        end

        self.dowloadRootUrl = dowloadRootUrl;
    else
        error("dislist中dowloadRootUrl未配置");
    end

    -- wifi不通，移动网络通，需要玩家确认下载
    local wifiConnected = NetworkStatus.isWifiConnected();
    local mobileConnected = NetworkStatus.isMobileConnected();
    if not wifiConnected and mobileConnected then
        am:setDownloadConfirmFlag(true);
    end

    am:retain();
    self.am = am;

    -- 注册事件处理回调函数
    self:registerEventCallback()

    -- 适配
    self:resize();

    -- 重绘
    self:redraw();
end

-- 适配
function UIPkgDownload:resize()
    local w = AlignM.frameSize.width;
    local h = AlignM.frameSize.height;

    -- bg2居中显示
    local bg = findChildByName(self.node, "bg2");
    bg:setPosition(w / 2, h / 2);
    local scaleCo = math.max(w / 768, h / 1136);
    bg:setScale(scaleCo);

    -- bg居中显示并充满整个屏幕
    AlignM.fitToScreen(self.node, "bg");

    -- BT置于底部并缩放至合适大小
    AlignM.alignToBottomCenter(self.node, "BT");
end

-- 重绘
function UIPkgDownload:redraw()
    -- 标题
    self.titleLabel = findChildByName(self.BT, "title");
    TextStyleM.setTextStyle(self.titleLabel, TextStyleM.TEXT_SIZE_MIDDLE, TextStyleM.TEXT_COLOR_ORANGE, true);
    self.titleLabel:setString(self.title);

    -- 提示
    self.tipLabel = findChildByName(self.BT, "tip_label");
    TextStyleM.setTextStyle(self.tipLabel, TextStyleM.TEXT_SIZE_SMALL2, TextStyleM.TEXT_COLOR_GRAY);
    self.tipLabel:setString(getLocStr("download_pkg_tip"));

    -- 背景图
    self:drawBgImage();

    -- 开始下载
    self:doAutoUpdate();
end

-- 注册事件处理回调函数
function UIPkgDownload:registerEventCallback()
    -- 界面析构后，需要清理下
    self:registerScriptHandler(function(eventType)
        if eventType == "exit" then
            cclog("UIPkgDownload 界面析构清理");
            if self.am then
                self.am:release();
            end

            if self.listener then
                print("removeEventListener");
                cc.Director:getInstance():getEventDispatcher():removeEventListener(self.listener);
            end

        elseif eventType == "enter" then
        end
    end);
end

-- 关闭界面
function UIPkgDownload:closeForm()
    closeFormByName("UIPkgDownload");

    local success = false;
    if self.targetVersion ~= nil then
        -- 强制更新版本时，返回成功
        success = true;
    else
        -- 下载单个独立包时，需要判断独立包标识是否已经设置
        success = (cc.UserDefault:getInstance():getStringForKey(self.targetPart) == "1");
    end

    if self.callback then
        self.callback(success, self.resultCode);

        -- 抛出分包下载完成事件
        if success == true then
            -- 抛出分包下载完成事件
            EventMgr.fire(event.END_PKG_DOWNLOAD, { ["targetPart"] = self.targetPart, });
        end
    end
end

-- 更新完毕，1秒后自动关闭当前界面
function UIPkgDownload:finish(status)
    self.pNode:setVisible(false);

    -- 更新完毕的动画
    self:finishEffect();

    local function close()
        -- 关闭界面
        self:closeForm();
    end

    performWithDelay(self, close, 3);
end

-- 执行自动更新
function UIPkgDownload:doAutoUpdate()
    local function showlog(msg)
        print(msg);

        if SHOW_AUTO_PATCH_LOG then
            if self.logLabel then
                self.logLabel:setString(msg);
            end
        end
    end

    -- 播放序列帧动画
    self:progressBarEffect();

    local am = self.am;
    if not am:getLocalManifest():isLoaded() then
        -- 更新失败，跳过
        showlog("local manifest not loaded");
        self:setUpdateResult(AP_NO_MANIFEST);
        self:showDownloadProgress(getCoreLocStr("status_completed"));
        self:finish();
    else
        local function onUpdateEvent(event)
            local eventCode = event:getEventCode();
            print("eventCode:"..eventCode);
            if eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_NO_LOCAL_MANIFEST then
                -- 无本地Mainifest文件，跳过
                showlog("ERROR_NO_LOCAL_MANIFEST");
                self:setUpdateResult(AP_NO_MANIFEST);
                self:showDownloadProgress(getCoreLocStr("status_completed"));
                self:finish();
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.NEED_CONFIRM then
                local totalSize = event:getTotalSize();
                if totalSize > 0 then
                    -- 显示下载确认框
                    self:showDownloadConfirm(totalSize);
                end
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_PROGRESSION then
                -- 单个文件更新进度
                local assetId = event:getAssetId();
                showlog("UPDATE_PROGRESSION: assetId = " .. tostring(assetId));
                if assetId == "@manifest" or assetId == "@version" then
                    self:showDownloadProgress(getCoreLocStr("status_check_res"));
                else
                    local percent = event:getPercent();
                    local totalSize = event:getTotalSize();

                    self:playUpdateAnimation(percent);

                    -- 显示已下载和总下载数据大小
                    if totalSize ~= 0 then
                        local msg = string.format("%d%% (%.1fM)", percent, totalSize/1024/1024);
                        self:showDownloadProgress(msg);

                        local printStr = string.format("assetId:%s update finished, percent:%d, %s",
                            assetId, percent, string.gsub(msg, ':', 'M'));
                        showlog(printStr);
                    end
                end
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.ASSET_UPDATED then
                -- 单个文件更新成功

            elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DOWNLOAD_MANIFEST or
                eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_PARSE_MANIFEST then
                -- 下载或解析Mainifest出错，跳过
                showlog("ERROR_DOWNLOAD_MANIFEST");
                self:setUpdateResult(AP_PARSE_MANIFEST_ERROR);
                self:showDownloadProgress(getCoreLocStr("status_completed"));
                self:finish();

                local errorMsg = "MSG: "..event:getMessage()..", URL: "..tostring(self.dowloadRootUrl);
                if DOWNLOAD_ERROR_REPORT_URL then
                    local errorMsg = string.format("%s %s", os.date(), tostring(errorMsg));
                    postDataToRemoteHost(DOWNLOAD_ERROR_REPORT_URL, errorMsg);
                end
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.ALREADY_UP_TO_DATE then
                self:setUpdateResult(AP_UPDATE_OK);
                self:showDownloadProgress(getCoreLocStr("status_updated"));
                self:finish();
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FINISHED then
                --在线更新成功
                showlog("UPDATE_FINISHED");
                self:setUpdateResult(AP_UPDATE_OK);
                self:showDownloadProgress(getCoreLocStr("status_completed"));
                self:finish();

                -- 设置独立包已经下载标记
                cc.UserDefault:getInstance():setStringForKey(self.targetPart, "1");
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_UPDATING then
                self:setUpdateResult(AP_FILE_DOWNLOAD_ERROR);

                local errorMsg = "ASSET: " .. event:getAssetId() .. ", ERROR: " .. event:getMessage();
                showlog(errorMsg);
                -- 某个文件下载失败
                local arr = string.explode(event:getAssetId(), "/");
                if #arr > 0 then
                    local errorMsg = "ERROR_UPDATING:" .. arr[#arr] .. ", " .. event:getMessage();
                    showlog(errorMsg);
                    self:showDownloadProgress(getLocStr("download_completed"));
                    self:finish();
                end

                if DOWNLOAD_ERROR_REPORT_URL then
                    local errorMsg = string.format("%s %s", os.date(), tostring(errorMsg));
                    postDataToRemoteHost(DOWNLOAD_ERROR_REPORT_URL, errorMsg);
                end
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.ERROR_DECOMPRESS
                or eventCode == cc.EventAssetsManagerEx.EventCode.NO_ENOUGH_STORAGE then
                -- 磁盘空间不足
                local errorMsg = "no enough storage";
                showlog(errorMsg);
                self:setUpdateResult(AP_NO_ENOUGH_STORAGE);
                self:finish();
                if DOWNLOAD_ERROR_REPORT_URL then
                    postDataToRemoteHost(DOWNLOAD_ERROR_REPORT_URL, errorMsg);
                end
            elseif eventCode == cc.EventAssetsManagerEx.EventCode.UPDATE_FAILED then
                showlog("UPDATE_FAILED");
                if self and self.finish then
                    self:finish();
                end
            end
        end
        self.listener = cc.EventListenerAssetsManagerEx:create(am,onUpdateEvent);
        cc.Director:getInstance():getEventDispatcher():addEventListenerWithFixedPriority(self.listener, 1);

        am:update();
    end
end

-- 设置更新结果
function UIPkgDownload:setUpdateResult(resultCode)
    self.resultCode = resultCode;
end

-- 显示下载确认框
function UIPkgDownload:showDownloadConfirm(totalSize)
    local function okFunc()
        -- 确认后继续下载
        self.am:update();
    end

    local function cancelFunc()
        -- 直接退出游戏
        exitApp();
    end

    local title = getCoreLocStr("package_download_title");
    local msg = string.format(getCoreLocStr("non_wifi_environment"), totalSize/1024/1024);
    nativeConfirm(title, msg, getCoreLocStr("btn_text_ok"), getCoreLocStr("btn_text_cancel"), okFunc, cancelFunc);
end

-- 显示下载量
function UIPkgDownload:showDownloadProgress(msg)
    if self.progressLabel then
        TextStyleM.setTextStyle(self.progressLabel, TextStyleM.TEXT_SIZE_SMALL, TextStyleM.TEXT_COLOR_WHITE, true, -1);
        self.progressLabel:setVisible(true);
        self.progressLabel:setString(msg);
    end
end

-- 显示背景图
function UIPkgDownload:drawBgImage()
    local bgImage = findChildByName(self.node, "bg2");

    -- 背景图列表
    local bgList = {"bg3", "bg4"};

    -- 随机加载一张背景图
    local index = math.random(1, #bgList);
    bgImage:loadTexture(getLoginIcon(bgList[index]));
end

-- 进度条冈布奥跳动动画
function UIPkgDownload:progressBarEffect()
    self.pNode:setVisible(true);
    local node = self.barEffect;
    local height = 20;

    local scaleX = node:getScaleX();
    local scaleY = node:getScaleY();
    local posY = node:getPositionY();

    -- 向上部分
    local moveUp = cc.EaseIn:create(cc.MoveTo:create(0.15, cc.p(node:getPositionX(), height)), 0.25);

    -- 下降部分
    local moveDown = cc.EaseOut:create(cc.MoveTo:create(0.15, cc.p(node:getPositionX(), posY)), 0.25);

    -- 还原
    local compressDown2 = cc.EaseOut:create(cc.ScaleTo:create(0.1, scaleX, scaleY-0.2), 2.5);
    local stretchUp2 = cc.EaseOut:create(cc.ScaleTo:create(0.05, scaleX, scaleY), 2.5);

    -- 动画
    node:runAction(cc.RepeatForever:create(cc.Sequence:create(moveUp, moveDown, compressDown2, stretchUp2)));
end

-- 更新动画
function UIPkgDownload:playUpdateAnimation(percent)
    -- 冈布奥的跳跃的位置
    local posX = self.loadingBar1BG:getContentSize().width / 100 * percent + 30;
    self.pNode:setPositionX(-self.loadingBar1BG:getContentSize().width/2 + posX);
    self.pNode:setVisible(true);

    self.lastPercent = self.lastPercent or 3.3;
    if self.lastPercent < percent and self.lastPercent < 99 then
        for i = self.lastPercent, percent, 3.3 do
            self:grassEffect(self.lastPercent);
            self.lastPercent = self.lastPercent + 3.3;
        end
        self.lastPercent = self.lastPercent + 3.3;
    elseif percent + 3.3 > self.lastPercent then
        self:grassEffect(percent);
        self.lastPercent = self.lastPercent + 3.3;
    end

    if percent > 93 then
        self.pNode:setVisible(false);
    end
end

-- 草地动画
function UIPkgDownload:grassEffect(percent)
    local curNum = math.floor(percent / 17.1);
    local curIndex = math.floor(math.floor(percent / 3.3) % 5);
    
    if math.floor(percent / 3.3) == 0 then
        curIndex = 1;
    else
        curIndex = (curIndex == 0) and 5 or curIndex;
    end

    local offset = 524 / 6 * curNum + grassOffset[curIndex] + 7;

    local grassImg = ccui.ImageView:create();
    local name = "g0" .. curIndex .. ".png";
    grassImg:loadTexture("images/ui/login/effect/" .. name, 1);
    grassImg:setAnchorPoint(0.5, 0.1);
    grassImg:setScale(0.05);

    local posX = self.loadingBar1BG:getContentSize().width/100 + offset;
    if posX > self.loadingBar1BG:getContentSize().width - 20 then
        grassImg:setVisible(false);
        return;
    end

    grassImg:setPosition(self.loadingBar1BG:getContentSize().width/100 + offset, offsetY);
    self.loadingBar1BG:addChild(grassImg);

    local time = math.random(1.5, 4) / 10;
    local scaleUp = cc.ScaleTo:create(time, 1.2);
    local scaleDown = cc.ScaleTo:create(time/5, 1);

    local function grassFlowerEffect(x, y, name)
        local flowerImg = ccui.ImageView:create();
        flowerImg:loadTexture("images/ui/login/effect/" .. name .. ".png", 1);
        flowerImg:setScale(0);
        flowerImg:setPosition(x, y);
        grassImg:addChild(flowerImg);

        local callFunc = cc.CallFunc:create(function()
            local flowerScaleUp = cc.ScaleTo:create(0.2, 1.2);
            local flowerScaleDown = cc.ScaleTo:create(0.05, 1);
            flowerImg:runAction(cc.Sequence:create(flowerScaleUp, flowerScaleDown));
        end);

        grassImg:runAction(cc.Sequence:create(scaleUp, scaleDown, callFunc));
    end

    if curIndex == 3 then
        grassFlowerEffect(20, 45, "f02");
    else
        local prob = math.random(0, 100);
        if prob > flowerProb then
            fX = math.random(0, 40);
            fY = math.random(25, 35);
            grassFlowerEffect(fX, fY, "f01");
        else
            grassImg:runAction(cc.Sequence:create(scaleUp, scaleDown));
        end
    end
end

-- 更新完毕的动画
function UIPkgDownload:finishEffect()
    -- 检查下有没有子节点，没有的话用通用的草地资源
    local childs = self.loadingBar1BG:getChildren();
    if not childs or #childs == 0 then
        local grassImg = ccui.ImageView:create();
        grassImg:loadTexture("images/ui/login/effect/progress.png");
        grassImg:setAnchorPoint(0.5, 0);
        grassImg:setPosition(self.loadingBar1BG:getContentSize().width/2, 3);
        self.loadingBar1BG:addChild(grassImg);
    end

    -- 更新完毕播放下进度条动画
    local scaleX = self.loadingBar1BG:getScaleX();
    local scaleY = self.loadingBar1BG:getScaleY();
    local scaleDown1 = cc.ScaleTo:create(0.1, scaleX, scaleY - 0.2);
    local scaleUp1   = cc.ScaleTo:create(0.1, scaleX, scaleY + 0.2);
    local scaleDown2 = cc.ScaleTo:create(0.1, scaleX, scaleY);

    self.loadingBar1BG:runAction(cc.Sequence:create(scaleDown1, scaleUp1, scaleDown2));
end
